Tegra: lib: library for profiling the cold boot path
authorVarun Wadekar <[email protected]>
Fri, 21 Jul 2017 20:34:16 +0000 (13:34 -0700)
committerVarun Wadekar <[email protected]>
Fri, 18 Jan 2019 17:21:51 +0000 (09:21 -0800)
The non secure world would like to profile the boot path for
the EL3 and S-EL1 firmwares. To allow it to do that, a non-secure
DRAM region (4K) is allocated and the base address is passed to
the EL3 firmware.

This patch adds a library to allow the platform code to store the
tag:timestamp pair to the shared memory. The tegra platform code
then uses the `record` method to add timestamps.

Original change by Akshay Sharan <[email protected]>

Change-Id: Idbbef9c83ed84a508b04d85a6637775960dc94ba
Signed-off-by: Varun Wadekar <[email protected]>
docs/plat/nvidia-tegra.rst
plat/nvidia/tegra/common/lib/debug/profiler.c [new file with mode: 0644]
plat/nvidia/tegra/common/tegra_bl31_setup.c
plat/nvidia/tegra/common/tegra_common.mk
plat/nvidia/tegra/include/lib/profiler.h [new file with mode: 0644]
plat/nvidia/tegra/include/tegra_private.h

index e244c1c99ae9b47ca67e9cb06187cc6704f0f6aa..90d2ae132b2d3c618379608dae472b34ccb2358f 100644 (file)
@@ -82,6 +82,8 @@ uint64\_t tzdram\_base;
 int uart\_id;
 /* L2 ECC parity protection disable flag \*/
 int l2\_ecc\_parity\_prot\_dis;
+/* SHMEM base address for storing the boot logs \*/
+uint64\_t boot\_profiler\_shmem\_base;
 } plat\_params\_from\_bl2\_t;
 
 Power Management
diff --git a/plat/nvidia/tegra/common/lib/debug/profiler.c b/plat/nvidia/tegra/common/lib/debug/profiler.c
new file mode 100644 (file)
index 0000000..f40244b
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*******************************************************************************
+ * The profiler stores the timestamps captured during cold boot to the shared
+ * memory for the non-secure world. The non-secure world driver parses the
+ * shared memory block and writes the contents to a file on the device, which
+ * can be later extracted for analysis.
+ *
+ * Profiler memory map
+ *
+ * TOP     ---------------------------      ---
+ *            Trusted OS timestamps         3KB
+ *         ---------------------------      ---
+ *         Trusted Firmware timestamps      1KB
+ * BASE    ---------------------------      ---
+ *
+ ******************************************************************************/
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <mmio.h>
+#include <profiler.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <utils_def.h>
+#include <xlat_tables_v2.h>
+
+static uint64_t shmem_base_addr;
+
+#define MAX_PROFILER_RECORDS   U(16)
+#define TAG_LEN_BYTES          U(56)
+
+/*******************************************************************************
+ * Profiler entry format
+ ******************************************************************************/
+typedef struct {
+       /* text explaining the timestamp location in code */
+       uint8_t tag[TAG_LEN_BYTES];
+       /* timestamp value */
+       uint64_t timestamp;
+} profiler_rec_t;
+
+static profiler_rec_t *head, *cur, *tail;
+static uint32_t tmr;
+static bool is_shmem_buf_mapped;
+
+/*******************************************************************************
+ * Initialise the profiling library
+ ******************************************************************************/
+void boot_profiler_init(uint64_t shmem_base, uint32_t tmr_base)
+{
+       uint64_t shmem_end_base;
+
+       assert(shmem_base != ULL(0));
+       assert(tmr_base != U(0));
+
+       /* store the buffer address */
+       shmem_base_addr = shmem_base;
+
+       /* calculate the base address of the last record */
+       shmem_end_base = shmem_base + (sizeof(profiler_rec_t) *
+                        (MAX_PROFILER_RECORDS - U(1)));
+
+       /* calculate the head, tail and cur values */
+       head = (profiler_rec_t *)shmem_base;
+       tail = (profiler_rec_t *)shmem_end_base;
+       cur = head;
+
+       /* timer used to get the current timestamp */
+       tmr = tmr_base;
+}
+
+/*******************************************************************************
+ * Add tag and timestamp to profiler
+ ******************************************************************************/
+void boot_profiler_add_record(const char *str)
+{
+       unsigned int len;
+
+       /* calculate the length of the tag */
+       if (((unsigned int)strlen(str) + U(1)) > TAG_LEN_BYTES) {
+               len = TAG_LEN_BYTES;
+       } else {
+               len = (unsigned int)strlen(str) + U(1);
+       }
+
+       if (head != NULL) {
+
+               /*
+                * The profiler runs with/without MMU enabled. Check
+                * if MMU is enabled and memmap the shmem buffer, in
+                * case it is.
+                */
+               if ((!is_shmem_buf_mapped) &&
+                   ((read_sctlr_el3() & SCTLR_M_BIT) != U(0))) {
+
+                       (void)mmap_add_dynamic_region(shmem_base_addr,
+                                       shmem_base_addr,
+                                       PROFILER_SIZE_BYTES,
+                                       (MT_NS | MT_RW | MT_EXECUTE_NEVER));
+
+                       is_shmem_buf_mapped = true;
+               }
+
+               /* write the tag and timestamp to buffer */
+               (void)snprintf((char *)cur->tag, len, "%s", str);
+               cur->timestamp = mmio_read_32(tmr);
+
+               /* start from head if we reached the end */
+               if (cur == tail) {
+                       cur = head;
+               } else {
+                       cur++;
+               }
+       }
+}
+
+/*******************************************************************************
+ * Deinint the profiler
+ ******************************************************************************/
+void boot_profiler_deinit(void)
+{
+       if (shmem_base_addr != ULL(0)) {
+
+               /* clean up resources */
+               cur = NULL;
+               head = NULL;
+               tail = NULL;
+
+               /* flush the shmem for it to be visible to the NS world */
+               flush_dcache_range(shmem_base_addr, PROFILER_SIZE_BYTES);
+
+               /* unmap the shmem buffer */
+               if (is_shmem_buf_mapped) {
+                       (void)mmap_remove_dynamic_region(shmem_base_addr,
+                                       PROFILER_SIZE_BYTES);
+               }
+       }
+}
index e92960c2eb406ccf89dcff5761ee8cdfeeaeda0e..80cc7129a1b333313db662b4626d9708b2f90ba6 100644 (file)
@@ -26,6 +26,7 @@
 #include <plat/common/platform.h>
 
 #include <memctrl.h>
+#include <profiler.h>
 #include <tegra_def.h>
 #include <tegra_platform.h>
 #include <tegra_private.h>
@@ -125,6 +126,7 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
        image_info_t bl32_img_info = { {0} };
        uint64_t tzdram_start, tzdram_end, bl32_start, bl32_end;
        uint32_t console_clock;
+       int32_t ret;
 
        /*
         * For RESET_TO_BL31 systems, BL31 is the first bootloader to run so
@@ -194,6 +196,32 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
                             TEGRA_CONSOLE_BAUDRATE);
        }
 
+       /*
+        * The previous bootloader passes the base address of the shared memory
+        * location to store the boot profiler logs. Sanity check the
+        * address and initilise the profiler library, if it looks ok.
+        */
+       if (plat_params->boot_profiler_shmem_base != 0ULL) {
+
+               ret = bl31_check_ns_address(plat_params->boot_profiler_shmem_base,
+                               PROFILER_SIZE_BYTES);
+               if (ret == (int32_t)0) {
+
+                       /* store the membase for the profiler lib */
+                       plat_bl31_params_from_bl2.boot_profiler_shmem_base =
+                               plat_params->boot_profiler_shmem_base;
+
+                       /* initialise the profiler library */
+                       boot_profiler_init(plat_params->boot_profiler_shmem_base,
+                                          TEGRA_TMRUS_BASE);
+               }
+       }
+
+       /*
+        * Add timestamp for platform early setup entry.
+        */
+       boot_profiler_add_record("[TF] early setup entry");
+
        /*
         * Initialize delay timer
         */
@@ -244,6 +272,11 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
        /* Early platform setup for Tegra SoCs */
        plat_early_platform_setup();
 
+       /*
+        * Add timestamp for platform early setup exit.
+        */
+       boot_profiler_add_record("[TF] early setup exit");
+
        INFO("BL3-1: Boot CPU: %s Processor [%lx]\n",
             (((read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK)
              == DENVER_IMPL) ? "Denver" : "ARM", read_mpidr());
@@ -268,6 +301,11 @@ void plat_trusty_set_boot_args(aapcs64_params_t *args)
  ******************************************************************************/
 void bl31_platform_setup(void)
 {
+       /*
+        * Add timestamp for platform setup entry.
+        */
+       boot_profiler_add_record("[TF] plat setup entry");
+
        /* Initialize the gic cpu and distributor interfaces */
        plat_gic_setup();
 
@@ -287,6 +325,11 @@ void bl31_platform_setup(void)
         */
        tegra_memctrl_tzram_setup(TEGRA_TZRAM_BASE, TEGRA_TZRAM_SIZE);
 
+       /*
+        * Add timestamp for platform setup exit.
+        */
+       boot_profiler_add_record("[TF] plat setup exit");
+
        INFO("BL3-1: Tegra platform setup complete\n");
 }
 
@@ -305,6 +348,12 @@ void bl31_plat_runtime_setup(void)
         * disabled before we jump to the non-secure world.
         */
        tegra_memctrl_disable_ahb_redirection();
+
+       /*
+        * Add final timestamp before exiting BL31.
+        */
+       boot_profiler_add_record("[TF] bl31 exit");
+       boot_profiler_deinit();
 }
 
 /*******************************************************************************
@@ -325,6 +374,11 @@ void bl31_plat_arch_setup(void)
 #endif
        const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
 
+       /*
+        * Add timestamp for arch setup entry.
+        */
+       boot_profiler_add_record("[TF] arch setup entry");
+
        /* add memory regions */
        mmap_add_region(rw_start, rw_start,
                        rw_size,
@@ -373,6 +427,11 @@ void bl31_plat_arch_setup(void)
        /* enable the MMU */
        enable_mmu_el3(0);
 
+       /*
+        * Add timestamp for arch setup exit.
+        */
+       boot_profiler_add_record("[TF] arch setup exit");
+
        INFO("BL3-1: Tegra: MMU enabled\n");
 }
 
index 6a0854ee25333af9c48d4044efb3ef87ac92f9cd..9428f43a717c05621542d6c5efaf1066959ca2cb 100644 (file)
@@ -5,6 +5,7 @@
 #
 
 PLAT_INCLUDES          :=      -Iplat/nvidia/tegra/include/drivers \
+                               -Iplat/nvidia/tegra/include/lib \
                                -Iplat/nvidia/tegra/include \
                                -Iplat/nvidia/tegra/include/${TARGET_SOC}
 
@@ -25,6 +26,7 @@ BL31_SOURCES          +=      drivers/console/aarch64/console.S               \
                                ${TEGRA_GICv2_SOURCES}                          \
                                ${COMMON_DIR}/aarch64/tegra_helpers.S           \
                                ${COMMON_DIR}/drivers/pmc/pmc.c                 \
+                               ${COMMON_DIR}/lib/debug/profiler.c              \
                                ${COMMON_DIR}/tegra_bl31_setup.c                \
                                ${COMMON_DIR}/tegra_delay_timer.c               \
                                ${COMMON_DIR}/tegra_fiq_glue.c                  \
diff --git a/plat/nvidia/tegra/include/lib/profiler.h b/plat/nvidia/tegra/include/lib/profiler.h
new file mode 100644 (file)
index 0000000..60f8d80
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PROFILER_H__
+#define __PROFILER_H__
+
+/*******************************************************************************
+ * Number of bytes of memory used by the profiler on Tegra
+ ******************************************************************************/
+#define PROFILER_SIZE_BYTES    U(0x1000)
+
+void boot_profiler_init(uint64_t shmem_base, uint32_t tmr_base);
+void boot_profiler_add_record(const char *str);
+void boot_profiler_deinit(void);
+
+#endif /* __PROFILER_H__ */
index c7636f61de89fb08e27787679b121497acfbd92b..f55f5df604e1eb85def7820fafbf94299fa23d4d 100644 (file)
@@ -44,6 +44,8 @@ typedef struct plat_params_from_bl2 {
        int32_t uart_id;
        /* L2 ECC parity protection disable flag */
        int32_t l2_ecc_parity_prot_dis;
+       /* SHMEM base address for storing the boot logs */
+       uint64_t boot_profiler_shmem_base;
 } plat_params_from_bl2_t;
 
 /*******************************************************************************